#ifndef _CONFIG_READER_H_
#define _CONFIG_READER_H_
#include <map>
#include <vector>
#include <string>
using namespace std;

#include "../tinyxml/tinyxml.h"
#include "../tinyxml/tinystr.h"
#include "ConfigLib.h"
#include <boost/noncopyable.hpp>


class CONFIGLIB_API ConfigReader
{
public:
	ConfigReader(void);
	~ConfigReader();
public:
	virtual bool Unload();
	virtual bool Load(const std::string& config_file="",
		bool bForceLoad=false);
	std::string GetFileName() const;
protected:
	TiXmlDocument *document;
	TiXmlElement  *root;
	std::string m_strFileName;
};

inline TiXmlElement* GetSubElement(TiXmlElement* parent, const std::string& tag_name,const std::string& strAttrName, const std::string& strAttrValue)
{
	TiXmlElement* sub_element = NULL;
	if (parent)
	{
		TiXmlElement* elem = NULL;
		if (tag_name.empty())
		{
			elem = parent->FirstChildElement();
		}
		else
		{
			elem = parent->FirstChildElement(tag_name.c_str());
		}
		while (elem)
		{
			const char* attrValue = elem->Attribute(strAttrName.c_str());
			if (attrValue && strAttrValue == attrValue) 
			{
				break;
			}
			if (tag_name.empty())
			{
				elem = elem->NextSiblingElement();
			}
			else
			{
				elem = elem->NextSiblingElement(tag_name.c_str());
			}
		}
	}
	return sub_element;
}

inline std::vector<TiXmlElement*> GetSubElements( TiXmlElement* parent,const std::string& tag_name="")
{
	std::vector<TiXmlElement*> sub_elements;
	if (parent)
	{
		TiXmlElement* elem=NULL;
		if (tag_name.empty())
		{
			elem = parent->FirstChildElement();
		}
		else
		{
			elem = parent->FirstChildElement(tag_name.c_str());
		}
		while (elem)
		{
			sub_elements.push_back(elem);
			if (tag_name.empty())
			{
				elem = elem->NextSiblingElement();
			}
			else
			{
				elem = elem->NextSiblingElement(tag_name.c_str());
			}
		}
	}
	return sub_elements;
}

inline std::string GetAttribute(TiXmlElement* elem, const std::string& attr_name, const std::string& defstr = "")
{
	if (elem)
	{
		const char* sz_attr_val = elem->Attribute(attr_name.c_str());
		if (NULL == sz_attr_val)
		{
			return defstr;
		}
		return std::string(sz_attr_val);
	}
	return defstr;
}

inline std::string GetAttribute(TiXmlElement* elem, const char* attr_name, const char* defstr = "")
{
	return GetAttribute(elem,std::string(attr_name),std::string(defstr));
}

inline std::string GetAttribute(TiXmlElement* elem, const std::string& attr_name, const char* defstr = "")
{
	return GetAttribute(elem, attr_name, std::string(defstr));
}

inline int GetAttribute(TiXmlElement* elem, const std::string& attr_name, int attrValue)
{
	if (elem)
	{
		const char* sz_attr_val = elem->Attribute(attr_name.c_str());
		if (NULL == sz_attr_val)
		{
			return attrValue;
		}
		return atoi(sz_attr_val);
	}
	return attrValue;
}

template<typename T>
inline bool GetAttribute(TiXmlElement* elem, const std::string& attr_name, T& attrValue)
{
	if (elem)
	{
		const char* sz_attr_val = elem->Attribute(attr_name.c_str());
		if (NULL == sz_attr_val)
		{
			return false;
		}
		std::stringstream ss(sz_attr_val);
		ss >> attrValue;
		return true;
	}
	return false;
}

inline std::map<std::string,std::string> GetAttributes(TiXmlElement* elem)
{
	std::map<std::string, std::string> result;
	if (elem)
	{
		for (TiXmlAttribute* pAttr = elem->FirstAttribute(); pAttr != NULL; pAttr = pAttr->Next())
		{
			std::string attrName = pAttr->Name();
			std::string attrValue = pAttr->Value();
			result[attrName] = attrValue;
		}
	}
	return result;
}

inline void SetAttribute(TiXmlElement* elem, const std::string& attr_name,const std::string& value)
{
	if (elem)
	{
		elem->SetAttribute(attr_name.c_str(),value.c_str());
	}
}

inline void SetAttribute(TiXmlElement* elem, const std::string& attr_name, double value)
{
	if (elem)
	{
		elem->SetDoubleAttribute(attr_name.c_str(), value);
	}
}

inline void SetAttribute(TiXmlElement* elem, const std::string& attr_name, int value)
{
	if (elem)
	{
		elem->SetAttribute(attr_name.c_str(), value);
	}
}


inline void SetInnerText(TiXmlElement* elem, const std::string& value)
{
	if (elem)
	{
		auto ptrTextNode = elem->FirstChild();
		TiXmlText* ptrText = dynamic_cast<TiXmlText*>(ptrTextNode);
		if (ptrText)
		{
			ptrText->SetValue(value.c_str());
		}
		else
		{
			ptrText = new TiXmlText(value.c_str());
			elem->LinkEndChild(ptrText);
		}
	}
}

inline std::string GetInnerText( TiXmlElement* elem )
{
	if (elem)
	{
		const char* sz_attr_val=elem->GetText();
		if (NULL==sz_attr_val)
		{
			return "";
		}
		return sz_attr_val;
	}
	return "";
}

#endif


